package controleur;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import modele.Joueur;
import modele.Plateau;
import modele.case_.Case;
import modele.pion.Pion;
import vue.AireDeJeu;
import vue.Fenetre;

/**
 * Classe abstraite qui détecte les mouvements et actions de la souris
 *
 * @author gervaila
 */
public abstract class EcouteurDeSouris implements MouseListener, MouseMotionListener {

	/**
	 * Le joueur qui a le trait
	 */
	protected Joueur joueurCourant;
	/**
	 * L'aire de jeu qui affiche le plateau
	 */
	protected AireDeJeu aire;
	/**
	 * Le plateau sur lequel se déroule la partie
	 */
	protected Plateau plateau;
	/**
	 * les coordonnées de survol la souris
	 */
	protected Point over;
	/**
	 * les coordonnées actuelles de la souris
	 */
	protected Point souris;
	/**
	 * la variation de coordonnées de la souris lors d'un survol
	 */
	protected Point deltaSouris;
	/**
	 * Détermine si le clic en cours est un clic droit
	 */
	protected boolean clicDroit;
	/**
	 * Joueur 1
	 */
	protected Joueur j1;
	/**
	 * Joueur 2
	 */
	protected Joueur j2;
	/**
	 * la Fenêtre dans laquelle est affichée l'aire de jeu que l'écouteur écoute
	 */
	protected Fenetre fenetre;

	/**
	 * Crée un écouteur de souris en fonction de l'aire qu'il observe
	 *
	 * @param aire	aire que l'écouteur va écouteur
	 * @param plateau plateau contenu dans l'aire de jeu
	 * @param j1 joueur 1
	 * @param j2 joueur 2
	 * @param f	fenetre qui contient l'aire de jeu à écouter
	 */
	public EcouteurDeSouris(AireDeJeu aire, Plateau plateau, Joueur j1, Joueur j2, Fenetre f) {
		this.aire = aire;
		this.plateau = plateau;
		over = new Point(-1, -1);
		clicDroit = false;
		souris = new Point(-1, -1);
		deltaSouris = new Point(-1, -1);
		this.j1 = j1;
		this.j2 = j2;
		joueurCourant = j1;
		this.fenetre = f;
	}

	/**
	 * Effectue une action en fonction de la case qui a été cliquée avec le
	 * bouton gauche.
	 *
	 * @param caseCliquee coordonnées de la case cliquée
	 */
	protected abstract void clicGaucheCase(Point caseCliquee);

	/**
	 * Effectue le changement de joueur courant
	 */
	public abstract void joueurSuivant();

	/**
	 * Defini la variable joueurCourant
	 *
	 * @param joueurCourant nouveau joueurCourant
	 */
	public void setJoueurCourant(Joueur joueurCourant) {
		this.joueurCourant = joueurCourant;
	}

	/**
	 * Retourne le joueurCourant actuel
	 *
	 * @return le joueurCourant
	 */
	public Joueur getJoueurCourant() {
		return joueurCourant;
	}

	/**
	 * Appelle les méthodes clicGauche ou clicDroit selon le bouton préssé par
	 * l'utilisateur
	 *
	 * @param e l'evenement de la souris
	 * @see MouseEvent
	 */
	@Override
	public void mousePressed(MouseEvent e) {
		int x = e.getX();
		int y = e.getY();
		Point caseCliquee = aire.getCaseCoordonnees(new Point(x, y));
		if (e.getButton() == MouseEvent.BUTTON1) {
			clicGaucheCase(caseCliquee);
		} else if (e.getButton() == MouseEvent.BUTTON3) {
			clicDroit = true;
			souris.x = x;
			souris.y = y;
		}
	}

	/**
	 * Signifie que clicDroit n'est plus valable pour le drag
	 *
	 * @param e l'evenement de la souris
	 * @see MouseEvent
	 */
	@Override
	public void mouseReleased(MouseEvent e) {
		clicDroit = false;
	}

	/**
	 * @param e l'evenement de la souris
	 * @see MouseEvent
	 */
	@Override
	public void mouseEntered(MouseEvent e) {
	}

	/**
	 * Masque les infos des pions lorsque la souris quitte l'aire de jeu
	 *
	 * @param e l'evenement de la souris
	 * @see MouseEvent
	 */
	@Override
	public void mouseExited(MouseEvent e) {
		over.x = -1;
		over.y = -1;
		aire.actualiserBuffers();
		mouseCaseChange(e, null);
	}

	/**
	 * @param e l'evenement de la souris
	 * @see MouseEvent
	 */
	@Override
	public void mouseClicked(MouseEvent e) {
	}

	/**
	 * Redéfini les coordonnées de la caméra et affiche le nouveau contenu de
	 * l'aire de jeu
	 *
	 * @param e l'evenement de la souris
	 * @see MouseEvent
	 */
	@Override
	public void mouseDragged(MouseEvent e) {
		if (clicDroit) {
			aire.masquerInfos();
			deltaSouris.x = e.getX() - souris.x;
			deltaSouris.y = e.getY() - souris.y;
			souris.x = e.getX();
			souris.y = e.getY();
			aire.setCamera(deltaSouris);
			aire.actualiserBuffers();

			fenetre.actualiserMiniMap();
		}
	}

	/**
	 * Si la souris passe au dessus d'un pion ses infos sont affichées et si
	 * elle quitte une case contenant un pion les infos sont masquées
	 *
	 * @param e l'evenement de la souris
	 * @see MouseEvent
	 */
	@Override
	public void mouseMoved(MouseEvent e) {
		//Afficher la bulle si on est sur une case qui contient un pion
		Point newCase = aire.getCaseCoordonnees(new Point(e.getX(), e.getY()));
		if (newCase.x != over.x || newCase.y != over.y) {
			over.x = newCase.x;
			over.y = newCase.y;
			Case c = plateau.getCase(over);
			mouseCaseChange(e, c);
		}
	}

	/**
	 * Defini les actions à effectuer lorsque la souris change de case
	 *
	 * @param e evènement de la souris
	 * @param c la Case sur laquelle se trouve la souris
	 */
	public void mouseCaseChange(MouseEvent e, Case c) {
		if (c != null) {
			Pion pion = c.getPion();
			if (pion != null) {
				aire.afficherInfos(over, pion);
			} else {
				aire.masquerInfos();
			}
		} else {
			aire.masquerInfos();
		}
	}
}
